home *** CD-ROM | disk | FTP | other *** search
/ Ian & Stuart's Australian Mac 1993 September / September 93.iso / Archives / Fun, Tricks & Hacks / Windows / Minesweeper.c next >
C/C++ Source or Header  |  1992-06-14  |  9KB  |  452 lines

  1. #include "MSWindows.h"
  2.  
  3. extern short     gSound;
  4. extern WindowPtr gMineWindow;
  5. extern RGBColor     gBlack,gWhite,gLtGray,gDkGray;
  6. extern PicHandle gPicts[];
  7.  
  8. // Game Globals
  9. Rect            gGameRect,
  10.                 gHdrRect,
  11.                 gFaceRect;
  12. Boolean            gRunning,
  13.                 gMarks = false,
  14.                 gNewGame;
  15.                 gEndGame;
  16. short            gFace;
  17.  
  18. unsigned long    gStartTime,now,then;
  19. short            rows,cols,mines;
  20. unsigned char    *pMineField = nil;
  21. unsigned char    *pMineView  = nil;
  22.  
  23. short            gGameType;
  24. short            colrange[]  = {12,16,30,16};
  25. short            rowrange[]  = {12,16,16,16};
  26. short            minerange[] = {20,40,99,40};
  27.  
  28. #pragma segment TheApp
  29. void
  30. NewGame(Boolean resize)
  31. {
  32.     short    r,c;
  33.     Rect bounds;
  34.  
  35.     GetDateTime(&gStartTime);
  36.     now = gStartTime;
  37.     cols = colrange[gGameType];
  38.     rows = rowrange[gGameType];
  39.     mines = minerange[gGameType];
  40.     if (pMineField) {
  41.         DisposPtr(pMineField);
  42.         DisposPtr(pMineView);
  43.     }
  44.     pMineField = NewPtrClear(rows*cols);
  45.     pMineView  = NewPtrClear(rows*cols);
  46.     for (r = 0; r < rows; r++)
  47.     for (c = 0; c < cols; c++)
  48.         mineview(r,c) = kButtonPict;
  49.     SetRect(&bounds,0,0,cols * kBox + 2*kBorder,rows * kBox + kHdrSize + kBorder);
  50.     gHdrRect = bounds;
  51.     gHdrRect.top = kBorderTop;    // skip MSWindow Hdr
  52.     gHdrRect.bottom = kHdrSize;
  53.     gFaceRect.top = kBorderTop + kInsetLCD;
  54.     gFaceRect.bottom = gFaceRect.top + kIconSize;
  55.     gFaceRect.left = (gHdrRect.right - kIconSize) / 2;
  56.     gFaceRect.right = gFaceRect.left + kIconSize;
  57.     gFace = kHappyFace;
  58.     gNewGame = true;
  59.     gEndGame = false;
  60.     gRunning = false;
  61.     SetPort(gMineWindow);
  62.     CreateGWorld(&bounds);
  63.     SizeWindow((WindowPtr)gMineWindow,bounds.right,bounds.bottom,true);    // fUpdate
  64.     ((MSWindowPtr)gMineWindow)->child->portRect = gMineWindow->portRect;
  65.     SizeMSWindow(((MSWindowPtr)gMineWindow)->child);
  66.     ClipRect(&bounds);
  67.     if (resize)
  68.         EraseRect(&bounds);
  69.     InvalRect(&bounds);            // force an update now
  70. }
  71.  
  72.  
  73. void
  74. InitGame(short rx,short cx)
  75. {
  76.     register short n,r,c,r1,c1,r2,c2;
  77.     unsigned long x;
  78.     
  79.     for (r = 0; r < rows; r++)
  80.     for (c = 0; c < cols; c++)
  81.         minefield(r,c) = 0;
  82.  
  83.     minefield(rx,cx) = kFlag;            // flag the original click cell        
  84.     n = mines;
  85.     while (0 < n) {
  86.         x = Random();
  87.         r1 = x & 0x7FFF;
  88.         r = r1 % rows;
  89.         r1 = (x >> 8) & 0x7FFF;
  90.         c = r1 % cols;
  91.         if ((minefield(r,c) & (~kNumMask)) == 0) {
  92.             minefield(r,c) = kMine;
  93.             r1 = (r == 0) ? 0 : r - 1;
  94.             r2 = (r >= rows - 1) ? rows - 1 : r + 1;
  95.             for ( ; r1 <= r2; r1++) {
  96.                 c1 = (c == 0) ? 0 : c - 1;
  97.                 c2 = (c >= cols - 1) ? cols - 1 : c + 1;
  98.                 for ( ; c1 <= c2; c1++) {
  99.                     if (minefield(r1,c1) != kMine)
  100.                         minefield(r1,c1)++;
  101.                 }
  102.             }
  103.             n--;
  104.         }
  105.     }
  106.     minefield(rx,cx) -= kFlag;        // unflag the original click cell    
  107.  
  108.     GetDateTime(&gStartTime);        // start timing the game now
  109.     now = gStartTime;
  110.     gNewGame = false;
  111.     gRunning = true;
  112. }
  113.  
  114. void
  115. GameTime(void)
  116. {
  117.     if (gRunning) {
  118.         GetDateTime(&now);
  119.         if (now != then) {
  120.             SetPort(gMineWindow);
  121.             InvalRect(&gHdrRect);
  122.         }
  123.     }
  124. }
  125. void
  126. DrawGame(BitMap *pixMap)
  127. {
  128.     if (gNewGame)
  129.         DrawNewMap(pixMap);
  130.     else
  131.         DrawHdr();
  132. }
  133.  
  134. unsigned char
  135. minechar(short r,short c)
  136. {
  137.     short v;
  138.     
  139.     v = minefield(r,c);
  140.     return ((v >= kMine) ? kBombPict: (v & kNumMask) + kNumPict);
  141. }
  142.  
  143. void
  144. DrawPict(short id,short *x,short *y)
  145. {
  146.     PicHandle pict;
  147.     Rect     box;
  148.     
  149.     if (pict = gPicts[id]) {
  150.         SetRect(&box,*x,*y,*x + (*pict)->picFrame.right,*y + (*pict)->picFrame.bottom);
  151.         DrawPicture(pict,&box);
  152.         *x += (*pict)->picFrame.right;
  153.     }
  154. }
  155.  
  156. void
  157. DrawLCD(short n,short x,short y)
  158. {
  159.     short i,j;
  160.     unsigned char v;
  161.     Str255    text;
  162.  
  163.     NumToString(n,&text);
  164.     for (i = 0; i < 3; i++) {
  165.         j = text[0] + i - 2;
  166.         v = (j > 0) ? text[j] - '0' : 0;
  167.         DrawPict(v + kLCDPict,&x,&y);
  168.     }
  169. }
  170.  
  171. void
  172. DrawBevel(Rect *box,short width,RGBColor *topColor,RGBColor *bottomColor)
  173. {
  174.     register short i,a,b1,b2;
  175.     
  176.     RGBForeColor(topColor);
  177.     PenSize(width,width);
  178.     FrameRect(box);
  179.     RGBForeColor(bottomColor);
  180.     PenNormal();
  181.     a = box->bottom-1;
  182.     b1 = box->left;
  183.     b2 = box->right-1;
  184.     for (i = 0; i < width; i++) {
  185.         MoveTo(b1++,a);
  186.         LineTo(b2--,a--);
  187.     }
  188.     a = box->right-1;
  189.     b1 = box->top;
  190.     b2 = box->bottom-1;
  191.     for (i = 0; i < width; i++) {
  192.         MoveTo(a,b1++);
  193.         LineTo(a--,b2--);
  194.     }
  195. }
  196.  
  197. void
  198. DrawFrame(void)
  199. {
  200.     short x,y;
  201.     Rect box,box1;
  202.     
  203.     box = gMineWindow->portRect;
  204.     box.top = kBorderTop;        // Header & menu bar
  205.     RGBForeColor(&gLtGray);
  206.     PaintRect(&box);
  207.  
  208.     DrawBevel(&box,kBorder1,&gWhite,&gDkGray);
  209.     
  210.     InsetRect(&box,kBorder1+kBorder2,kBorder1+kBorder2);
  211.     box1 = box;
  212.     box1.bottom = box1.top + 2*kBorderLCD + +2* kBorder3h + kHeightLCD;
  213.     DrawBevel(&box1,kBorder3h,&gDkGray,&gWhite);
  214.     
  215.     box1 = box;
  216.     box1.top = kHdrSize - kBorder3;
  217.     DrawBevel(&box1,kBorder3,&gDkGray,&gWhite);
  218.     
  219.     RGBForeColor(&gDkGray);
  220.     x = kInsetLCD;
  221.     y = kBorderTop + kInsetLCD + kHeightLCD - 1;
  222.     MoveTo(x,kBorderTop + kInsetLCD);
  223.     LineTo(x,y);
  224.     RGBForeColor(&gWhite);
  225.     x += 3*kWidthLCD + 1;
  226.     MoveTo(x,kBorderTop + kInsetLCD);
  227.     LineTo(x,y);
  228.     RGBForeColor(&gDkGray);
  229.     x = gMineWindow->portRect.right - kInsetLCD - 3*kWidthLCD - 2;
  230.     MoveTo(x,kBorderTop + kInsetLCD);
  231.     LineTo(x,y);
  232.     RGBForeColor(&gWhite);
  233.     x += 3*kWidthLCD + 1;
  234.     MoveTo(x,kBorderTop + kInsetLCD);
  235.     LineTo(x,y);
  236.     RGBForeColor(&gBlack);
  237. }
  238.  
  239. void
  240. DrawHdr(void)
  241. {
  242.     DrawCell(gFace,&gFaceRect);
  243.  
  244.     DrawLCD(mines,kInsetLCD + 1,kBorderTop + kInsetLCD);
  245.     
  246.     GetDateTime(&now);
  247.     DrawLCD(now - gStartTime,gMineWindow->portRect.right - kInsetLCD - 3*kWidthLCD - 1,
  248.         kBorderTop + kInsetLCD);
  249.     then = now;
  250. }
  251.  
  252. void
  253. DrawCell(short id,Rect *box)
  254. {
  255.     PicHandle pict;
  256.     
  257.     if (pict = gPicts[id])
  258.         DrawPicture(pict,box);
  259. }
  260.  
  261. void
  262. DrawNewMap(BitMap *pixMap)
  263. {
  264.     short    r,c;
  265.     Rect    box,box1;
  266.     
  267.     DrawFrame();
  268.     DrawHdr();
  269.     SetRect(&box,kBorder,kHdrSize,kBorder+kBox,kHdrSize+kBox);
  270.     r = 0;
  271.     for (c = 0; c < cols; c++) {
  272.         DrawCell(mineview(r,c),&box);
  273.         box.left += kBox;
  274.         box.right += kBox;
  275.     }
  276.     box.left = kBorder;
  277.     box.right -= kBox;
  278.     gGameRect = box;
  279.     for (r = 1; r < rows; r++) {
  280.         box1 = box;
  281.         box.top += kBox;
  282.         box.bottom += kBox;
  283.         CopyBits(pixMap,pixMap,&box1,&box,srcCopy,nil);
  284.     }
  285.     gGameRect.bottom = box.bottom;
  286. }
  287.  
  288. void
  289. DrawMap(void)
  290. {
  291.     short    r,c;
  292.     Rect    box;
  293.     
  294.     DrawHdr();
  295.     SetRect(&box,kBorder,kHdrSize,kBorder+kBox,kHdrSize+kBox);
  296.     for (r = 0; r < rows; r++) {
  297.         box.left = kBorder;
  298.         box.right = box.left + kBox;
  299.         for (c = 0; c < cols; c++) {
  300.             DrawCell(mineview(r,c),&box);
  301.             box.left += kBox;
  302.             box.right += kBox;
  303.         }
  304.         box.top += kBox;
  305.         box.bottom += kBox;
  306.     }
  307. }
  308.  
  309. void
  310. ClickMines(void)
  311. {
  312.     short    r,c,x,y;
  313.     unsigned char v,v1;
  314.     Rect    box;
  315.  
  316.     for (r = 0; r < rows; r++) {
  317.         for (c = 0; c < cols; c++) {
  318.             v = minechar(r,c);
  319.             if (v == kBombPict)
  320.                 v1 = v;
  321.             else
  322.             if (mineview(r,c) == kFlagPict)    // misidentified
  323.                 v1 = kBadPict;
  324.             else
  325.                 v1 = 0;
  326.             if (v1 != 0) {
  327.                 mineview(r,c) = v1;
  328.                 x = c * kBox + kBorder;
  329.                 y = r * kBox + kHdrSize;
  330.                 SetRect(&box,x,y,x + kBox,y + kBox);
  331.                 DrawCell(v1,&box);
  332.             }
  333.         }
  334.     }
  335.     gFace = kSadFace;
  336.     gEndGame = true;
  337. }
  338.  
  339. void
  340. ClickNeighbors(r,c)
  341. {
  342.     short    r1,c1,r2,c2,x,y;
  343.     unsigned char v;
  344.     Rect    box;
  345.  
  346.     r1 = (r == 0) ? 0 : r - 1;
  347.     r2 = (r >= rows - 1) ? rows - 1 : r + 1;
  348.     for ( ; r1 <= r2; r1++) {
  349.         c1 = (c == 0) ? 0 : c - 1;
  350.         c2 = (c >= cols - 1) ? cols - 1 : c + 1;
  351.         for ( ; c1 <= c2; c1++) {
  352.             v = minechar(r1,c1);
  353.             if (mineview(r1,c1) == kButtonPict) {    // currently unturned or unflagged
  354.                 mineview(r1,c1) = v;
  355.                 x = c1 * kBox + kBorder;
  356.                 y = r1 * kBox + kHdrSize;
  357.                 SetRect(&box,x,y,x + kBox,y + kBox);
  358.                 DrawCell(v,&box);
  359.                 if (v == kNumPict)
  360.                     ClickNeighbors(r1,c1);
  361.             }
  362.         }
  363.     }
  364. }
  365.  
  366. Boolean PtInGame(Point where)
  367. {
  368.     return (PtInRect(where,&gGameRect) || PtInRect(where,&gFaceRect));
  369. }
  370.  
  371. void
  372. ClickGame(Point where,short modifiers)
  373. {
  374.     Boolean result = false;
  375.     
  376. reclick:
  377.     while (StillDown()) {
  378.         GetMouse(&where);
  379.         if (PtInRect(where,&gGameRect) && (!gEndGame))
  380.             ClickCell(where,modifiers);
  381.         else
  382.         if (PtInRect(where,&gFaceRect)) {
  383.             DrawCell(kPressedFace,&gFaceRect);
  384.             while (StillDown()) {
  385.                 GetMouse(&where);
  386.                 if (!PtInRect(where,&gFaceRect)) {    // dragged out of the box
  387.                     DrawCell(gFace,&gFaceRect);
  388.                     goto reclick;                    // try again
  389.                 }
  390.             }
  391.             NewGame(false);
  392.         }
  393.     }
  394. }
  395.  
  396. void
  397. ClickCell(Point where,short modifiers)
  398. {
  399.     unsigned char v;
  400.     short    r,c,x,y;
  401.     Rect    box;
  402.     
  403.     DrawCell(kOwFace,&gFaceRect);
  404.     where.h -= kBorder;
  405.     where.v -= kHdrSize;
  406.     r = where.v / kBox;
  407.     c = where.h / kBox;
  408.     x = c * kBox + kBorder;
  409.     y = r * kBox + kHdrSize;
  410.     SetRect(&box,x,y,x + kBox,y + kBox);
  411.     if (mineview(r,c) == kButtonPict)
  412.         DrawCell(kEmptyPict,&box);
  413.     while (StillDown()) {
  414.         GetMouse(&where);
  415.         if (!PtInRect(where,&box)) {    // dragged out of the box
  416.             if (mineview(r,c) == kButtonPict)
  417.                 DrawCell(kButtonPict,&box);
  418.             if (!PtInRect(where,&gGameRect))    // dragged out of the game
  419.                 DrawCell(gFace,&gFaceRect);
  420.             return;                                // try new box
  421.         }
  422.     }
  423.     if (gNewGame)
  424.         InitGame(r,c);
  425.     if (mineview(r,c) == kMarkPict) {    // was a mark flag
  426.         v = kButtonPict;
  427.     } else
  428.     if (mineview(r,c) == kFlagPict) {    // was a bomb flag
  429.         mines++;
  430.         v = (gMarks) ? kMarkPict : kButtonPict;
  431.     } else
  432.     if (modifiers) {            // any modifier key down
  433.         v = kFlagPict;
  434.         mines--;
  435.     } else {                    // just a clean click
  436.         v = minechar(r,c);
  437.         if (v == kBombPict) {
  438.             if (gSound) SysBeep(4);
  439.             ClickMines();
  440.             v = kBoomPict;        // we blew up
  441.         }
  442.     }
  443.     mineview(r,c) = v;
  444.     DrawCell(v,&box);
  445.     if (v == kNumPict)            // this cell has no surrounding bombs
  446.         ClickNeighbors(r,c);
  447.     DrawHdr();
  448.     SaveBits(gMineWindow);
  449.     gRunning = (mines != 0);
  450. }
  451.  
  452.